rpi3: Introduce hardware RNG driver
authorAntonio Nino Diaz <[email protected]>
Fri, 13 Jul 2018 08:27:16 +0000 (09:27 +0100)
committerAntonio Nino Diaz <[email protected]>
Mon, 16 Jul 2018 14:56:42 +0000 (15:56 +0100)
Note that this is a non-secure RNG. This is only useful for educational
purposes.

Change-Id: If359c8d0f755ef8e416986de7fbca34679a523e1
Signed-off-by: Antonio Nino Diaz <[email protected]>
plat/rpi3/rpi3_hw.h
plat/rpi3/rpi3_private.h
plat/rpi3/rpi3_rng.c [new file with mode: 0644]

index a83a0ad16082dd151b20e2a479e2980a33b15736..1a26053b935cdd90b136681241348b9293e793ec 100644 (file)
  */
 #define RPI3_PM_RSTS_WRCFG_HALT                U(0x00000555)
 
+/*
+ * Hardware random number generator.
+ */
+#define RPI3_IO_RNG_OFFSET             ULL(0x00104000)
+#define RPI3_RNG_BASE                  (RPI3_IO_BASE + RPI3_IO_RNG_OFFSET)
+#define RPI3_RNG_CTRL_OFFSET           ULL(0x00000000)
+#define RPI3_RNG_STATUS_OFFSET         ULL(0x00000004)
+#define RPI3_RNG_DATA_OFFSET           ULL(0x00000008)
+#define RPI3_RNG_INT_MASK_OFFSET       ULL(0x00000010)
+/* Enable/disable RNG */
+#define RPI3_RNG_CTRL_ENABLE           U(0x1)
+#define RPI3_RNG_CTRL_DISABLE          U(0x0)
+/* Number of currently available words */
+#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT        U(24)
+#define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF)
+/* Value to mask interrupts caused by the RNG */
+#define RPI3_RNG_INT_MASK_DISABLE      U(0x1)
+
 /*
  * Serial port (called 'Mini UART' in the BCM docucmentation).
  */
index 9d1744e3fd9530fd29a0dbc01f984861411f4fcd..91b7add854b9374491e4e7a1ad715d80e79e6437 100644 (file)
@@ -33,6 +33,9 @@ uint32_t rpi3_get_spsr_for_bl33_entry(void);
 /* IO storage utility functions */
 void plat_rpi3_io_setup(void);
 
+/* Hardware RNG functions */
+void rpi3_rng_read(void *buf, size_t len);
+
 /* VideoCore firmware commands */
 int rpi3_vc_hardware_get_board_revision(uint32_t *revision);
 
diff --git a/plat/rpi3/rpi3_rng.c b/plat/rpi3/rpi3_rng.c
new file mode 100644 (file)
index 0000000..111b3b6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <mmio.h>
+#include <string.h>
+
+#include "rpi3_hw.h"
+
+/* Initial amount of values to discard */
+#define RNG_WARMUP_COUNT       U(0x40000)
+
+static void rpi3_rng_initialize(void)
+{
+       uint32_t int_mask, ctrl;
+
+       /* Return if it is already enabled */
+       ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET);
+       if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) {
+               return;
+       }
+
+       /* Mask interrupts */
+       int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET);
+       int_mask |= RPI3_RNG_INT_MASK_DISABLE;
+       mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask);
+
+       /* Discard several values when initializing to give it time to warmup */
+       mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT);
+
+       mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET,
+                     RPI3_RNG_CTRL_ENABLE);
+}
+
+static uint32_t rpi3_rng_get_word(void)
+{
+       size_t nwords;
+
+       do {
+               /* Get number of available words to read */
+               nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET)
+                                      >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT)
+                                      & RPI3_RNG_STATUS_NUM_WORDS_MASK;
+       } while (nwords == 0U);
+
+       return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET);
+}
+
+void rpi3_rng_read(void *buf, size_t len)
+{
+       uint32_t data;
+       size_t left = len;
+       uint32_t *dst = buf;
+
+       assert(buf != NULL);
+       assert(len != 0U);
+       assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0);
+
+       rpi3_rng_initialize();
+
+       while (left >= sizeof(uint32_t)) {
+               data = rpi3_rng_get_word();
+               *dst++ = data;
+               left -= sizeof(uint32_t);
+       }
+
+       if (left > 0U) {
+               data = rpi3_rng_get_word();
+               memcpy(dst, &data, left);
+       }
+}